/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * This example demonstrates usage of filters for received data, listing of
 * available services and how to subscribe to them.
 */

#include "gimi.h"

int main(void) {
  int count = 0, result = 0;
  std::string hubname = "asrobo.hut.fi";
  int hubport = 50002;
  std::string targetname = "gimitutorialservice";
  std::string ownname = "gimitutorialsubscriber";

  // Initialize dPrint.
  debugInit();
  debugSetGlobalDebugLvl(6);
  
  // Create the GIMI-object.
  dPrint(1, "Create object.");
  gimi::GIMI gi;

  // Create an object to store messages. (Structure described in gimimessage.h)
  gimi::GIMIMessage message;

  // Object to store list of services
  gimi::t_serviceList serviceList;

  // Add filtering by type, so GIMI rejects datapackets that are not of
  // permitted types. If no permitted types are defined, then all are allowed.
  if (!gi.addWantedTypeId(8000, 0)) {
    dPrint(1, "Given typeid is already on wanted list.");
    return -1;
  }
  if (!gi.addWantedTypeId(8000, 1)) {
    dPrint(1, "Given typeid is already on wanted list.");
    return -1;
  }
  // You can also filter by sender id. If no permitted senders are defined,
  // all are allowed.
  
  // Connect to tcphub.
  if (!gi.connectToHub(hubname, hubport, ownname)) {
    dPrint(1, "Could not connect to tcpHub. Are connection parameters correct?");
    return -1;
  }

  // Query services from a single client
  result = gi.serviceDiscoveryToTarget(serviceList, targetname, 5000);
  if (result != GIMI_OK) {
    dPrint(1, "Servicediscovery to %s failed with error %d (%s).",
           targetname.c_str(), result, gimi::getGimiErrorString(result).c_str());
  } else {
    dPrint(1, "Servicediscovery to %s success.", targetname.c_str());

    // Iterate through the list.
    printf("List of services on %s:\n", targetname.c_str());
    for (gimi::t_serviceListConstIterator iter = serviceList.begin();
         iter != serviceList.end();
         ++iter)
    {
      if (iter->majorServiceId == GIMI_PROTOCOL_CLIENT_DESCRIPTION) {
        printf("[0x%08x] %s ::", iter->clientId, (iter->clientName).c_str());
        if (!(iter->serviceDescription).empty()) {
          printf(" %s", (iter->serviceDescription).c_str());
        }
        if (iter->clientVersion.getVersion() != 0) {
          printf(" v.%s",
                 iter->clientVersion.getVersionString().c_str());
        }
        if (!(iter->serviceLocation).empty()) {
          printf(" @ %s", (iter->serviceLocation).c_str());
        }
        printf(" using GIMI version %s\n",
               ((iter->gimiVersion).getVersionString()).c_str());
      } else {
        printf("[0x%08x] %s :: %s %d",
               iter->clientId,
               (iter->clientName).c_str(),
               (iter->getShortServiceTypeString()).c_str(),
               iter->majorServiceId);
        if (iter->minorServiceId >= 0) {
          printf(":%d", iter->minorServiceId);
        }
          // Write name & description for datatype if found.
        gimi::DataTypeDefinition dtdef;
        if (gimi::datatypeDefinitions.getDatatype(dtdef, iter->majorServiceId)) {
          printf(" (%s, %s)", dtdef.dataTypeName.c_str(),
                 dtdef.dataTypeDescription.c_str());
        }
        if (!(iter->serviceDescription).empty()) {
          printf(" %s", (iter->serviceDescription).c_str());
        }
        if (!(iter->serviceLocation).empty()) {
          printf(" @ %s", (iter->serviceLocation).c_str());
        }
        printf("\n");
      }
    }
  }
  
  // Query services from all clients.
  printf("Sending servicediscovery to all clients.\n");
  result = gi.serviceDiscovery(serviceList, 5000);
  if (result == GIMI_OK) {
    printf("Got services:\n");
    for (gimi::t_serviceListConstIterator iter = serviceList.begin();
         iter != serviceList.end();
         ++iter)
    {
      if (iter->majorServiceId == GIMI_PROTOCOL_CLIENT_DESCRIPTION) {
        printf("[0x%08x] %s ::", iter->clientId, (iter->clientName).c_str());
        if (!(iter->serviceDescription).empty()) {
          printf(" %s", (iter->serviceDescription).c_str());
        }
        if (iter->clientVersion.getVersion() != 0) {
          printf(" v.%s",
                 iter->clientVersion.getVersionString().c_str());
        }
        if (!(iter->serviceLocation).empty()) {
          printf(" @ %s", (iter->serviceLocation).c_str());
        }
        printf(" using GIMI version %s\n",
               ((iter->gimiVersion).getVersionString()).c_str());
      } else {
        printf("[0x%08x] %s :: %s %d",
               iter->clientId,
               (iter->clientName).c_str(),
               (iter->getShortServiceTypeString()).c_str(),
               iter->majorServiceId);
        if (iter->minorServiceId >= 0) {
          printf(":%d", iter->minorServiceId);
        }
          // Write name & description for datatype if found.
        gimi::DataTypeDefinition dtdef;
        if (gimi::datatypeDefinitions.getDatatype(dtdef, iter->majorServiceId)) {
          printf(" (%s, %s)", dtdef.dataTypeName.c_str(),
                 dtdef.dataTypeDescription.c_str());
        }
        if (!(iter->serviceDescription).empty()) {
          printf(" %s", (iter->serviceDescription).c_str());
        }
        if (!(iter->serviceLocation).empty()) {
          printf(" @ %s", (iter->serviceLocation).c_str());
        }
        printf("\n");
      }
    }
  } else {
    dPrint(1, "Servicediscovery to all failed with error %d (%s).",
           result, gimi::getGimiErrorString(result).c_str());
  }

  // Subscribe to a service.
  result = gi.subscribeToService(targetname, 8000, 0);
  if (result != GIMI_OK) {
    dPrint(1, "Subscribing service 8000:0 from %s failed with error %d (%s).",
           targetname.c_str(), result, gimi::getGimiErrorString(result).c_str());
    return -1;
  }

  // Subscribe to service with automatic resubscription if no data is received
  // within 5000ms.
  result = gi.subscribeToService(targetname, 8000, 1, 2000, 5000);
  if (result != GIMI_OK) {
    dPrint(1, "Subscribing service 8000:1 from %s failed with error %d (%s).",
           targetname.c_str(), result, gimi::getGimiErrorString(result).c_str());
    return -1;
  }

  // Receive 50 messages.
  while(count < 50) {
    // Receive without timeout, waits until a message arrives.
    if (gi.receive(message, -1) == GIMI_OK) { 
      printf("Got message with majortype: %d minortype: %d msgid: %d from: 0x%08x with flags: %d "
           "arrived: %ld.06%ld data: ",
           message.majorTypeId, message.minorTypeId, message.messageId,
           message.senderId, message.messageFlags, message.arrivalTime.seconds,
           message.arrivalTime.useconds);
      printf("%s\n", message.data);
      ++count;
    } else {
      printf("Receive gave error %d (%s).\n", result,
             gimi::getGimiErrorString(result).c_str());
    }
  }
  
  // GIMI-destructor handles disconnecting

  // Closes logfile in case if it was used. (dPrint)
  debugDeinit();
  
  return 0;
}
